#  This file is part of OpenLightingDesigner.
# 
#  OpenLightingDesigner is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  OpenLightingDesigner is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with OpenLightingDesigner.  If not, see <http://www.gnu.org/licenses/>.
#
# effectpalette.py
# Copyright (c) 2010 - 2011 Matthew Reid

from Bases import BaseObject, setID

from controller import controllerTypes

class EffectPalette(BaseObject):
    _saved_class_name = 'EffectPalette'
    _saved_attributes = ['id', 'name', 'all_groups', 'group_names', 'obj_ids', 'default_duration', 'prototype_id']
    #_saved_child_objects = ['effects']
    def __init__(self, **kwargs):
        self.saved_child_classes = [Effect]
        self._sequencer = None
        super(EffectPalette, self).__init__(**kwargs)
        self.register_signal('settings_changed', 'sequencer_state')
        if 'deserialize' not in kwargs:
            self.id = setID(kwargs.get('id'))
            self.name = kwargs.get('name', '')
            self.default_duration = kwargs.get('duration', 2)
            self.all_groups = kwargs.get('all_groups', False)
            self.group_names = set()
            self.obj_ids = set()
            self.effects = {}
        self.sequencer = kwargs.get('sequencer')
        self.group_obj = {}
        groups = kwargs.get('group_names', [])
        for g in groups:
            self.add_group_name(g)
        
        ptype = kwargs.get('prototype')
        if ptype is not None:
            self.prototype_id = ptype.id
            for key, val in ptype.effects.iteritems():
                d = val._get_saved_attr()['attrs'].copy()
                d.update({'effect_prototype':val})
                d.update({'controller_prototype':val.controller_prototype})
                e = self.add_effect(**d)
                #val.connect('settings_changed', e.on_settings_changed)
        else:
            self.prototype_id = None
        self.prototype = ptype
            
    def unlink(self):
        for e in self.effects.itervalues():
            e.unlink()
        super(EffectPalette, self).unlink()
        #if self.prototype:
        #    self.prototype.unbind(self)
#        for key, val in self.prototype.effects.iteritems():
#            e = self.effects.get(key)
#            if e:
#                val.disconnect(callback=e.on_settings_changed)
    
    def add_group_name(self, group):
        self.group_names.add(group)
        for e in self.effects.itervalues():
            e.add_group_name(group)
    
    def add_obj(self, obj):
        self.group_obj.update({obj.id:obj})
        self.obj_ids.add(obj.id)
        for e in self.effects.itervalues():
            e.add_obj(obj)
        
    def del_obj(self, key):
        for e in self.effects.itervalues():
            e.del_obj(key)
        if key in self.group_obj:
            del self.group_obj[key]
        self.obj_ids.discard(key)
        
    @property
    def sequencer(self):
        return self._sequencer
    @sequencer.setter
    def sequencer(self, value):
        if self.sequencer:
            self.sequencer.disconnect(callback=self.on_sequencer_state_changed)
        self._sequencer = value
        for e in self.effects.itervalues():
            e.sequencer = value
        if self.sequencer:
            self.sequencer.connect('state_changed', self.on_sequencer_state_changed)
            
    def add_effect(self, **kwargs):
        '''
        :Parameters:
            id :
            name :
            controller_type : str, ('Functional, Keyframe')
            group_names : group names to be affected
        '''
        kwargs.update({'sequencer':self.sequencer, 'all_groups':self.all_groups})
        e = Effect(**kwargs)
        for g in self.group_names:
            e.add_group_name(g)
        for obj in self.group_obj.itervalues():
            e.add_obj(obj)
        self.effects.update({e.id:e})
        self.emit('settings_changed', effect=e)
        return e
        
    def del_effect(self, **kwargs):
        key = kwargs.get('id')
        e = kwargs.get('effect', self.effects.get(key))
        if e is None:
            return
        e.unlink()
        del self.effects[e.id]
        self.emit('settings_changed', del_effect=e)
        
    def on_sequencer_state_changed(self, **kwargs):
        self.emit('sequencer_state', **kwargs)
        
    def on_settings_changed(self, **kwargs):
        if 'effect' in kwargs:
            e = kwargs.get('effect')
            if e.id not in self.effects:
                d = e._get_saved_attr()['attrs'].copy()
                d.update({'effect_prototype':e})
                d.update({'controller_prototype':e.controller_prototype})
                new_e = self.add_effect(**d)
                #e.connect('settings_changed', new_e.on_settings_changed)
        elif 'del_effect' in kwargs:
            e = kwargs.get('del_effect')
            self.del_effect(id=e.id)
        
#controllerTypes = {'Keyframe':KeyframeController, 'Functional':FunctionalController}

class Effect(BaseObject):
    _saved_class_name = 'Effect'
    _saved_attributes = ['id', 'name', 'controller_type', 'obj_ids']
    #_saved_child_objects = ['controllers', 'controller_prototype']
    def __init__(self, **kwargs):
        self.saved_child_classes = controllerTypes.values()
        super(Effect, self).__init__(**kwargs)
        self.register_signal('settings_changed')
        self.all_groups = kwargs.get('all_groups', False)
        if 'deserialize' not in kwargs:
            self.id = setID(kwargs.get('id'))
            self.name = kwargs.get('name', '')
            self.controller_type = kwargs.get('controller_type', 'Functional')
            self.controllers = {}
            self.obj_ids = set()
            cls = controllerTypes.get(self.controller_type)
            c = kwargs.get('controller_prototype')
            if c is not None:
                c_kwargs = c._get_saved_attr()['attrs'].copy()
                c_kwargs['prototype'] = c
                new_c = cls(**c_kwargs)
                #c.connect('settings_changed', new_c.on_settings_changed)
            else:
                new_c = cls(name=self.name)
            self.controller_prototype = new_c
            self.controller_supertype = c
            
        self.effect_prototype = kwargs.get('effect_prototype')
        #if self.effect_prototype:
        #    self.effect_prototype.connect('settings_changed', self.on_settings_changed)
        self._sequencer = kwargs.get('sequencer')
        self.group_obj = {}
        self.group_names = set()
        
    def unlink(self):
        for key, c in self.controllers.copy().iteritems():
            if self.sequencer:
                self.sequencer.del_controller(c)
            c.unlink()
            if c.id in self.controllers:
                del self.controllers[c.id]
            elif key in self.controllers:
                del self.controllers[key]
            else:
                self.LOG.warning('cannot delete: ', c.id)
        super(Effect, self).unlink()
        #if self.effect_prototype is not None:
        #    self.effect_prototype.disconnect(callback=self.on_settings_changed)
        #if self.controller_supertype is not None:
        #    self.controller_supertype.disconnect(callback=self.controller_prototype.on_settings_changed)
        
        #for key in self.controllers.keys()[:]:
        #    c = self.controllers[key]
        #    if self.sequencer:
        #        self.sequencer.del_controller(c)
        #    c.unlink()
        #    del self.controllers[key]
        
    @property
    def sequencer(self):
        return self._sequencer
    @sequencer.setter
    def sequencer(self, value):
        old = self._sequencer
        self._sequencer = value
        if old is None and value is not None:
            for c in self.controllers.itervalues():
                self.sequencer.add_controller(c)
    
    def add_group_name(self, group):
        self.group_names.add(group)
        self.assign_controllers()
        self.emit('settings_changed', group_name=group)
    
    def add_obj(self, obj):
        if obj.id in self.group_obj:
            return
        self.group_obj.update({obj.id:obj})
        self.obj_ids.add(obj.id)
        self.assign_controllers()
        
    def del_obj(self, key):
        if key in self.controllers:
            self.controllers[key].unlink()
            del self.controllers[key]
        if key in self.group_obj:
            del self.group_obj[key]
        self.obj_ids.discard(key)
        
    def store_value(self, **kwargs):
        timeV = kwargs.get('timeV')
        objkey = kwargs.get('objkey')
        value = kwargs.get('value')
        if objkey:
            if True:#self.all_groups:
                objval = self.controllers.get(objkey)
            elif False:
                for grkey, grval in self.controllers.iteritems():
                    objval = grval.get(objkey)
                    if objval:
                        break
            if objval:
                objval.store_value(timeV, value)
            else:
                pass
                #print 'key not found:', objkey
        else:
            if self.all_groups:
                for c in self.controllers.itervalues():
                    c.store_value(timeV, value)                        
            elif False:
                for grval in self.controllers.itervalues():
                    for c in grval.itervalues():
                        if type(c) == list:
                            for realc in c:
                                realc.store_value(timeV, value)
                        else:
                            c.store_value(timeV, value)
                        
    def set_expression(self, **kwargs):
        objkey = kwargs.get('objkey')
        expression = kwargs.get('expression')
        if objkey:
            objval = self.controllers.get(objkey)
            if objval:
                objval.expression = expression
        else:
            for c in self.controllers.itervalues():
                c.expression = expression
                
    def get_expression(self, **kwargs):
        objkey = kwargs.get('objkey')
        if objkey:
            objval = self.controllers.get(objkey)
            if not objval:
                return
            return objval.expression
        keys = self.controllers.keys()
        return dict(zip(keys, [self.controllers[key].expression for key in keys]))
        
    def set_time_offset(self, **kwargs):
        objkey = kwargs.get('objkey')
        offset = kwargs.get('offset')
        if objkey:
            objval = self.controllers.get(objkey)
            if objval:
                objval.time_offset = offset
        else:
            for c in self.controllers.itervalues():
                c.time_offset = offset
        
    def assign_controllers(self):
        if self.all_groups:
            for objkey, objval in self.group_obj.iteritems():
                base = getattr(objval, 'base_class', None)
                if objkey not in self.controllers:
                    if base == 'Group' or base == 'Attribute':
                        c = self._build_controller(obj=objval)
                        self.controllers.update({objkey:c})
            #print self, 'controllers: ', self.controllers
        else:
            for objkey, objval in self.group_obj.iteritems():
                base = getattr(objval, 'base_class', None)
                if objkey not in self.controllers:
                    if base == 'Group' and objval.name in self.group_names:
                        c = self._build_controller(obj=objval)
                        self.controllers.update({objkey:c})
#        elif False:
#            for grkey in self.group_names:
#                if grkey not in self.controllers:
#                    self.controllers.update({grkey:{}})
#                for objkey, objval in self.group_obj.iteritems():
#                    if objval.saved_class_name == 'DeviceGroup':
#                        if grkey in objval.AttributeGroups and objkey not in self.controllers[grkey]:
#                            c = self._build_controller(obj=objval.AttributeGroups[grkey])
#                            self.controllers[grkey].update({objkey:c})
#                            print 'effect=%s, controller=%s, obj=%s' % (self.name, c, objval)
#                    elif getattr(objval, 'base_class') == 'Group':
#                        if grkey.lower() in objval.saved_class_name.lower() and objkey not in self.controllers[grkey]:
#                            if type(objval.value) == list:
#                                self.controllers[grkey].update({objkey:[]})
#                                for index in range(len(objval.value)):
#                                    c = self._build_controller(obj=objval, index=index)
#                                    self.controllers[grkey][objkey].append(c)
#                                    print 'effect=%s, controller=%s, index=%s, obj=%s' % (self.name, c, index, objval)
#                            else:
#                                c = self._build_controller(obj=objval)
#                                self.controllers[grkey].update({objkey:c})
#                                print 'effect=%s, controller=%s, obj=%s' % (self.name, c, objval)
            
    def _build_controller(self, **kwargs):
        id = kwargs.get('id')
        obj = kwargs.get('obj')
        attr = getattr(obj, 'value_attribute', 'value')
        d = self.controller_prototype._get_saved_attr()['attrs']
        #d.update({'src_object':obj, 'src_attr':attr})
        d.update({'Property':(obj, attr), 'prototype':self.controller_prototype})
        if isinstance(getattr(obj, attr), dict):
            cls = controllerTypes['Multi']
            d['controller_type'] = self.controller_type
        else:
            cls = controllerTypes.get(self.controller_type)
        c = cls(**d)
        if self.sequencer:
            self.sequencer.add_controller(c)
        #self.controller_prototype.connect('settings_changed', c.on_settings_changed)
        return c
        
    def on_controller_update(self, **kwargs):
        pass
        
    def on_settings_changed(self, **kwargs):
        if 'group_name' in kwargs:
            self.add_group_name(kwargs.get('group_name'))
            
    def _deserialize_child(self, d):
        pass
        

